﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace OAuthAccess
{
    internal static class OAuthUtility
    {
        private static Random random = new Random(DateTime.Now.Millisecond);

        private static string GetTimeStamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }

        private static string GetNonce()
        {
            return Guid.NewGuid().ToString();
        }

        internal static string GenerateAuthorizationHeader(
            string realm,
            string url,HttpMethodType type,
            Consumer consumer,
            TokenBase token,string verifier,
            IEnumerable<Parameter> args)
        {
            List<Parameter> authorizationHeaderParameters = new List<Parameter>
            {
                 new Parameter() { Key = "oauth_consumer_key", Value = consumer.ConsumerKey },
                 new Parameter() { Key = "oauth_signature_method", Value = "HMAC-SHA1" },
                 new Parameter() { Key = "oauth_timestamp", Value = OAuthUtility.GetTimeStamp() },
                 new Parameter() { Key = "oauth_nonce", Value = OAuthUtility.GetNonce() },
                 new Parameter() { Key = "oauth_version", Value = "1.0" }
            };

            if (token != null)
            {
                authorizationHeaderParameters.Add(new Parameter() { Key = "oauth_token", Value = token.Token });
            }

            if (verifier != null)
            {
                authorizationHeaderParameters.Add(new Parameter() { Key = "oauth_verifier", Value = verifier });
            }

            StringBuilder headerBase = new StringBuilder("OAuth ");

            if (!string.IsNullOrEmpty(realm))
            {
                headerBase = headerBase.Append(string.Format("realm=\"{0}\",", realm));
            }

            headerBase.Append(string.Join(",",
                authorizationHeaderParameters.Select(
                (p) => { return p.Key + "=" + "\"" + p.Value + "\""; }
                ).ToArray()));

            headerBase.Append("," + "oauth_signature=\"" + GenerateSignature(consumer, token, type, url, authorizationHeaderParameters, args) + "\"");

            return headerBase.ToString();
        }

        private static string GenerateSignature(
            Consumer c,TokenBase token,HttpMethodType type,
            string url,
            IEnumerable<Parameter> oAuthParameters,
            IEnumerable<Parameter> parameters)
        {
            string key = c.ConsumerSecret.OAuthPercentEncode() + "&" + (token == null ? string.Empty : token.TokenSecret.OAuthPercentEncode());

            string method;

            switch (type)
            {
                case HttpMethodType.Get:
                    method = "GET";
                    break;
                case HttpMethodType.Post:
                    method = "POST";
                    break;
                default:
                    method = null;
                    break;
            }

            string baseUrl = url.OAuthPercentEncode();

            IEnumerable<Parameter> allParas = oAuthParameters.Union(parameters);

            var sortedParas = from p in allParas
                              orderby p.Key, p.Value ascending
                              select p.Key + "=" + p.Value.OAuthPercentEncode();

            string paras = string.Join("&", sortedParas.ToArray());

            string signatureBaseString = method + "&" + baseUrl + "&" + paras.OAuthPercentEncode();

            byte[] hash;

            using (HMACSHA1 pro = new HMACSHA1())
            {
                pro.Key = Encoding.ASCII.GetBytes(key);

                hash = pro.ComputeHash(Encoding.ASCII.GetBytes(signatureBaseString));
            }

            return Convert.ToBase64String(hash).OAuthPercentEncode();
        }
    }
}
